# -*- coding: utf-8 -*-
"""
Redis缓存服务类
用于知识库文章的缓存管理
"""

import json
import redis
from django.conf import settings
from typing import List, Dict, Optional
import logging

logger = logging.getLogger(__name__)


class KnowledgeCacheService:
    """知识库缓存服务"""
    
    def __init__(self):
        # Redis连接配置 - 可在settings中配置
        self.redis_config = getattr(settings, 'REDIS_CONFIG', {
            'host': 'localhost',
            'port': 6379,
            'db': 0,
            'decode_responses': True
        })
        
        # 缓存键前缀
        self.prefix = "knowledge:"
        
        # 缓存过期时间（秒）
        self.expire_time = {
            'categories': 3600,  # 1小时
            'articles': 1800,    # 30分钟
            'hot_tags': 600,     # 10分钟
        }
        
        try:
            self.redis_client = redis.Redis(**self.redis_config)
            # 测试连接
            self.redis_client.ping()
            self.redis_available = True
            logger.info("Redis连接成功")
        except Exception as e:
            self.redis_available = False
            logger.warning(f"Redis连接失败，将使用内存缓存: {e}")
            # 内存缓存fallback
            self._memory_cache = {}
    
    def _get_key(self, key_type: str, identifier: str = "") -> str:
        """生成缓存键"""
        if identifier:
            return f"{self.prefix}{key_type}:{identifier}"
        return f"{self.prefix}{key_type}"
    
    def get_categories(self) -> Optional[List[Dict]]:
        """获取分类缓存"""
        key = self._get_key("categories")
        
        if self.redis_available:
            try:
                cached_data = self.redis_client.get(key)
                if cached_data:
                    return json.loads(cached_data)
            except Exception as e:
                logger.error(f"Redis获取分类缓存失败: {e}")
        else:
            # 内存缓存fallback
            return self._memory_cache.get(key)
        
        return None
    
    def set_categories(self, categories: List[Dict]) -> bool:
        """设置分类缓存"""
        key = self._get_key("categories")
        
        if self.redis_available:
            try:
                self.redis_client.setex(
                    key, 
                    self.expire_time['categories'], 
                    json.dumps(categories, ensure_ascii=False)
                )
                return True
            except Exception as e:
                logger.error(f"Redis设置分类缓存失败: {e}")
        else:
            # 内存缓存fallback
            self._memory_cache[key] = categories
            return True
        
        return False
    
    def get_articles(self, category_id: int = None, page: int = 1, 
                    page_size: int = 12, sort_by: str = 'latest', 
                    search_query: str = '') -> Optional[Dict]:
        """获取文章列表缓存"""
        # 构建缓存键
        cache_params = f"cat_{category_id}_p_{page}_ps_{page_size}_sort_{sort_by}_q_{search_query}"
        key = self._get_key("articles", cache_params)
        
        if self.redis_available:
            try:
                cached_data = self.redis_client.get(key)
                if cached_data:
                    return json.loads(cached_data)
            except Exception as e:
                logger.error(f"Redis获取文章缓存失败: {e}")
        else:
            # 内存缓存fallback
            return self._memory_cache.get(key)
        
        return None
    
    def set_articles(self, articles_data: Dict, category_id: int = None, 
                    page: int = 1, page_size: int = 12, sort_by: str = 'latest', 
                    search_query: str = '') -> bool:
        """设置文章列表缓存"""
        # 构建缓存键
        cache_params = f"cat_{category_id}_p_{page}_ps_{page_size}_sort_{sort_by}_q_{search_query}"
        key = self._get_key("articles", cache_params)
        
        if self.redis_available:
            try:
                self.redis_client.setex(
                    key, 
                    self.expire_time['articles'], 
                    json.dumps(articles_data, ensure_ascii=False)
                )
                return True
            except Exception as e:
                logger.error(f"Redis设置文章缓存失败: {e}")
        else:
            # 内存缓存fallback
            self._memory_cache[key] = articles_data
            return True
        
        return False
    
    def get_article_detail(self, article_id: int) -> Optional[Dict]:
        """获取文章详情缓存"""
        key = self._get_key("article_detail", str(article_id))
        
        if self.redis_available:
            try:
                cached_data = self.redis_client.get(key)
                if cached_data:
                    return json.loads(cached_data)
            except Exception as e:
                logger.error(f"Redis获取文章详情缓存失败: {e}")
        else:
            return self._memory_cache.get(key)
        
        return None
    
    def set_article_detail(self, article_id: int, article_data: Dict) -> bool:
        """设置文章详情缓存"""
        key = self._get_key("article_detail", str(article_id))
        
        if self.redis_available:
            try:
                self.redis_client.setex(
                    key, 
                    self.expire_time['articles'], 
                    json.dumps(article_data, ensure_ascii=False)
                )
                return True
            except Exception as e:
                logger.error(f"Redis设置文章详情缓存失败: {e}")
        else:
            self._memory_cache[key] = article_data
            return True
        
        return False
    
    def get_hot_tags(self) -> Optional[List[str]]:
        """获取热门标签缓存"""
        key = self._get_key("hot_tags")
        
        if self.redis_available:
            try:
                cached_data = self.redis_client.get(key)
                if cached_data:
                    return json.loads(cached_data)
            except Exception as e:
                logger.error(f"Redis获取热门标签缓存失败: {e}")
        else:
            return self._memory_cache.get(key)
        
        return None
    
    def set_hot_tags(self, tags: List[str]) -> bool:
        """设置热门标签缓存"""
        key = self._get_key("hot_tags")
        
        if self.redis_available:
            try:
                self.redis_client.setex(
                    key, 
                    self.expire_time['hot_tags'], 
                    json.dumps(tags, ensure_ascii=False)
                )
                return True
            except Exception as e:
                logger.error(f"Redis设置热门标签缓存失败: {e}")
        else:
            self._memory_cache[key] = tags
            return True
        
        return False
    
    def invalidate_cache(self, pattern: str = None) -> bool:
        """清除缓存"""
        if pattern:
            key_pattern = f"{self.prefix}{pattern}*"
        else:
            key_pattern = f"{self.prefix}*"
        
        if self.redis_available:
            try:
                keys = self.redis_client.keys(key_pattern)
                if keys:
                    self.redis_client.delete(*keys)
                return True
            except Exception as e:
                logger.error(f"Redis清除缓存失败: {e}")
        else:
            # 清除内存缓存
            keys_to_delete = [k for k in self._memory_cache.keys() if k.startswith(key_pattern.replace('*', ''))]
            for key in keys_to_delete:
                del self._memory_cache[key]
            return True
        
        return False
    
    def update_article_stats(self, article_id: int, read_increment: int = 0, 
                           like_increment: int = 0) -> bool:
        """更新文章统计信息"""
        if not self.redis_available:
            return False
        
        try:
            # 使用Redis Hash存储文章统计
            stats_key = self._get_key("article_stats", str(article_id))
            
            if read_increment > 0:
                self.redis_client.hincrby(stats_key, "read_count", read_increment)
            
            if like_increment != 0:
                self.redis_client.hincrby(stats_key, "like_count", like_increment)
            
            # 设置过期时间
            self.redis_client.expire(stats_key, 86400)  # 24小时
            
            return True
        except Exception as e:
            logger.error(f"Redis更新文章统计失败: {e}")
            return False
    
    def get_article_stats(self, article_id: int) -> Dict:
        """获取文章统计信息"""
        if not self.redis_available:
            return {}
        
        try:
            stats_key = self._get_key("article_stats", str(article_id))
            stats = self.redis_client.hgetall(stats_key)
            return {
                'read_count': int(stats.get('read_count', 0)),
                'like_count': int(stats.get('like_count', 0))
            }
        except Exception as e:
            logger.error(f"Redis获取文章统计失败: {e}")
            return {}


# 全局缓存服务实例
knowledge_cache = KnowledgeCacheService()